/*******************************************************************************
 * Copyright (c) 2009, 2013 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 * IBM - Initial API and implementation
 *******************************************************************************/
package org.eclipse.cdt.make.xlc.core.scannerconfig;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;

import org.eclipse.cdt.make.core.scannerconfig.IScannerInfoCollector2;
import org.eclipse.cdt.make.core.scannerconfig.ScannerInfoTypes;
import org.eclipse.cdt.make.internal.core.scannerconfig.util.CCommandDSC;
import org.eclipse.cdt.make.internal.core.scannerconfig.util.TraceUtil;
import org.eclipse.cdt.make.xlc.core.activator.Activator;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;

/**
 * @author crecoskie
 *
 */
@SuppressWarnings("restriction")
public class XLCPerFileBuildOutputParser extends AbstractXLCBuildOutputParser {

	/* (non-Javadoc)
	 * @see org.eclipse.cdt.make.xlc.core.scannerconfig.AbstractXLCBuildOutputParser#processCommand(java.lang.String[])
	 */
	@Override
	protected boolean processCommand(String[] tokens) {
		try {

		// GCC C/C++ compiler invocation
		int compilerInvocationIndex = findCompilerInvocation(tokens);
		if (compilerInvocationIndex < 0) {
			return false;
		}

		// find a file name
		int extensionsIndex = -1;
		boolean found = false;
		String filePath = null;

		// check for automake format first
		// e.g. line will start with
		// source='/some/path/source.cpp'
		int automakeSrcIndex = findAutoMakeSourceIndex(tokens);
		if(automakeSrcIndex != -1) {
			filePath = getAutoMakeSourcePath(tokens[automakeSrcIndex]);
			int k = filePath.lastIndexOf('.');
			if (k != -1 && (filePath.length() - k < 5)) {
				String fileExtension = filePath.substring(k);
				extensionsIndex = getFileExtensionsList().indexOf(fileExtension);
				if (extensionsIndex != -1) {
					found = true;
				}
			}
		}

		if (!found) {
			for (int i = compilerInvocationIndex + 1; i < tokens.length; i++) {
				String token = tokens[i];
				int k = token.lastIndexOf('.');
				if (k != -1 && (token.length() - k < 5)) {
					String fileExtension = token.substring(k);
					extensionsIndex = getFileExtensionsList().indexOf(fileExtension);
					if (extensionsIndex != -1) {
						filePath = token;
						found = true;
						break;
					}
				}
			}
		}

		if (!found) {
			TraceUtil.outputTrace("Error identifying file name :1", tokens, TraceUtil.EOL); //$NON-NLS-1$
			return false;
		}
		// sanity check
		if (filePath.indexOf(getFileExtensions()[extensionsIndex]) == -1) {
			TraceUtil.outputTrace("Error identifying file name :2", tokens, TraceUtil.EOL); //$NON-NLS-1$
			return false;
		}
		if (getUtility() != null) {
			IPath pFilePath = fUtility.getAbsolutePath(filePath);
			String shortFileName = pFilePath.removeFileExtension().lastSegment();

			// generalize occurrences of the file name
			for (int i = compilerInvocationIndex + 1; i < tokens.length; i++) {
				String token = tokens[i];
				if (token.equals("-include")) { //$NON-NLS-1$
					++i;
				} else if (token.equals("-imacros")) { //$NON-NLS-1$
					++i;
				} else if (token.equals(filePath)) {
					tokens[i] = "LONG_NAME"; //$NON-NLS-1$
				} else if (token.startsWith(shortFileName)) {
					tokens[i] = token.replaceFirst(shortFileName, "SHORT_NAME"); //$NON-NLS-1$
				}
			}

			IFile file = null;
			IPath baseDirectory = fUtility.getBaseDirectory();
			if (baseDirectory.isPrefixOf(pFilePath)) {
				IPath relPath = pFilePath.removeFirstSegments(baseDirectory.segmentCount());
				// Note: We add the scanner-config even if the resource doesn't
				// actually
				// exist below this project (which may happen when reading
				// existing
				// build logs, because resources can be created as part of the
				// build
				// and may not exist at the time of analyzing the config but
				// re-built
				// later on.
				// if (getProject().exists(relPath)) {
				file = getProject().getFile(relPath);
			} else {
				file = getUtility().findFileInWorkspace(pFilePath);
			}
			if (true /*file != null*/) {
				CCommandDSC cmd = getUtility().getNewCCommandDSC(tokens, compilerInvocationIndex, extensionsIndex > 0);
				List<CCommandDSC> cmdList = new CopyOnWriteArrayList<CCommandDSC>();
				cmdList.add(cmd);
				Map<ScannerInfoTypes, List<CCommandDSC>> sc = new HashMap<ScannerInfoTypes, List<CCommandDSC>>(1);
				sc.put(ScannerInfoTypes.COMPILER_COMMAND, cmdList);
				getCollector().contributeToScannerConfig(file, sc);
				if (fCollector != null && fCollector instanceof IScannerInfoCollector2) {
					IScannerInfoCollector2 collector = (IScannerInfoCollector2) fCollector;
					try {
						collector.updateScannerConfiguration(null);
					} catch (CoreException e) {
						// TODO Auto-generated catch block
						Activator.log(e);
					}
				}
			} else {
				/*
				//TraceUtil.outputError("Build command for file outside project: " + pFilePath.toString(), tokens); //$NON-NLS-1$
				// put the info on the project
				//CCommandDSC cmd = getUtility().getNewCCommandDSC(tokens, compilerInvocationIndex, extensionsIndex > 0);
				//List<CCommandDSC> cmdList = new ArrayList<CCommandDSC>();
//				cmdList.add(cmd);
				Map<ScannerInfoTypes, List<?>> sc = new HashMap<ScannerInfoTypes, List<?>>();
//				sc.put(ScannerInfoTypes.COMPILER_COMMAND, cmdList);


				// put in empty info for the other types
				sc.put(ScannerInfoTypes.INCLUDE_PATHS, new LinkedList<String>());
				sc.put(ScannerInfoTypes.SYMBOL_DEFINITIONS, new LinkedList<String>());

				getCollector().contributeToScannerConfig(getProject(), sc);
				if (fCollector != null && fCollector instanceof IScannerInfoCollector2) {
					IScannerInfoCollector2 collector = (IScannerInfoCollector2) fCollector;
					try {
						collector.updateScannerConfiguration(null);
					} catch (CoreException e) {
						// TODO Auto-generated catch block
						Activator.log(e);
					}
				}

				*/
			}
		}
 		return true;

		}
		catch(Throwable e) {
			e.printStackTrace();
			return false;
		}
	}

	protected String getAutoMakeSourcePath(String string) {
		// path may be enclosed in single quotes
		int firstQuoteIndex = string.indexOf('\'');
		int lastQuoteIndex = string.lastIndexOf('\'');
		if(firstQuoteIndex != -1 && lastQuoteIndex != -1)
			return string.substring(firstQuoteIndex, lastQuoteIndex);
		else {
			// just take everything after the equals sign
			int equalsIndex = string.indexOf('=');
			if(equalsIndex != -1 && equalsIndex < string.length())
				return string.substring(equalsIndex+1);

		}
		return null;
	}

	protected int findAutoMakeSourceIndex(String[] tokens) {
		for (int i = 0; i < tokens.length; i++) {
			final String token = tokens[i].toLowerCase();
			if(token.indexOf("source=") != -1) //$NON-NLS-1$
				return i;
		}
		return -1;
	}

}
